<template>
  <div
    class="game-area-container"
    @click="handleClickCloseSetting"
    :style="{
      width: `${sizeW}px`,
      height: `${sizeH}px`,
    }"
  >
    <div
      class="area-container"
      :style="{
        width: `${sizeW}px`,
        height: `${sizeH}px`,
      }"
    >
      <template class="cardIconBox" v-for="item in infoStore.gameCards">
        <CardIcon
          v-if="infoStore.gameIsShowCards[item.cardId + '']"
          :key="item.cardId + '-' + item.iconId"
          :cardSize="cardSize"
          :coor="{ x: item.coor.x, y: item.coor.y }"
          :cardId="item.cardId"
          :iconId="item.iconId"
          :borColor="colorStore.borColor[0]"
        />
        <!-- :color="colorStore.word[0]"
          :bg="colorStore.cardBg[0]" -->
      </template>
      <!-- <CardIcon
        v-if="isShowCards['5']"
        :cardId="0"
        :cardSize="cardSize"
        :coor="{ x: 5, y: 3 }"
        :iconId="1"
        @cardClick="handleCardClick"
      /> -->
      <div class="msg">
        {{
          infoStore.isLevelMode
            ? "卡片消除数: " + this.infoStore.clearCard
            : "幸运值: " + parseInt(this.infoStore.cardProb * 1000) / 10 + "%"
        }}
      </div>
      <div class="versions" @click="handleShowCmd">{{ versionTxt }}</div>
      <div class="curCardNum" v-show="cardStore.isShowCurCard">
        {{ "剩余卡片: " + curNum }}
      </div>
    </div>
  </div>
</template>

<script>
import delay from "@/utils/delay";
import CardIcon from "@/components/CardIcon";
import getRandom from "@/utils/getRandom";
import clickVoice from "@/assets/audio/clickVoice/1.mp3";
import voice1 from "@/assets/audio/clickVoice/5.mp3";
import closeTips from "@/utils/closeTips";
export default {
  components: {
    CardIcon,
  },
  props: {
    // 游戏区 宽度/高度 [密排的情况下每 行/列 的最大的卡片数]
    size: {
      type: Object,
      default: () => ({ w: 10, h: 10 }),
    },
    // 卡片尺寸
    cardSize: {
      type: Number,
      required: 60,
    },
    // 初始卡片数
    cardNum: {
      type: Number,
      default: 96,
    },
    // 是否自动添加卡片
    isAutoAddCard: {
      type: Boolean,
      default: false,
    },
    // 自动添加卡片的时间间隔
    duration: {
      type: Number,
      default: 3500,
    },
  },
  data() {
    return {
      infoStore: this.$store.state.info,
      cardStore: this.$store.state.cards,
      colorStore: this.$store.state.color,
      versionStore: this.$store.state.versions,
      isLoading: false, // 是否正在加载卡片
      clickNum: 0, // 点击版本号的次数
    };
  },
  mounted() {
    // 监听游戏开始事件
    this.$bus.$on("gameStart", this.handleGameStart);
    // 监听游戏区的卡片点击事件
    this.$bus.$on("gameCardClick", this.handleGameCardClick);
  },
  beforeDestroy() {
    // 移除监听
    this.$bus.$off("gameStart", this.handleGameStart);
    this.$bus.$off("gameCardClick", this.handleGameCardClick);
  },
  computed: {
    // 当前版本号
    versionTxt() {
      const versions =
        this.versionStore.versions3 ||
        this.versionStore.versions2 ||
        this.versionStore.versions;
      return versions[versions.length - 1].title.slice(
        2,
        versions[versions.length - 1].title.length
      ); // 游戏的当前版本号
    },
    // 游戏区的实际宽度 [px]
    sizeW() {
      return (this.size.w + 1) * (this.cardSize / 2);
    },
    // 游戏区的实际高度 [px]
    sizeH() {
      return (this.size.h + 1) * (this.cardSize / 2);
    },
    // 当前卡片数
    curNum() {
      return this.infoStore.gameCards.length;
    },
  },
  methods: {
    // 多次点击后显示cmd窗口
    async handleShowCmd() {
      // 在3s内点击超过6次将显示cmd窗口
      if (this.cardStore.isShowCmd) {
        this.$store.commit("cards/setIsShowCmd", false);
      }
      this.clickNum++;
      await delay(3000);
      if (this.clickNum >= 6) {
        console.log("显示命令窗口");
        this.$store.commit("cards/setIsShowCmd", true);
      }
      this.clickNum = 0;
    },
    // 播放音效
    playVoice(voiceUrl, volume = 1) {
      if (this.infoStore.isVolume) {
        var player = new Audio(voiceUrl);
        player.volume = volume; // 设置音量
        player.play(); //播放 mp3这个音频对象
      }
    },
    // 点击后关闭设置窗口和卡片池窗口
    handleClickCloseSetting() {
      // this.$store.commit("info/setIsShowSetting", false);
      this.$bus.$emit("clickSetting", false);
      this.$bus.$emit("clickCardPool", true);
      closeTips();
    },
    // 验证当前位置的卡片是否可点击
    isCardClick(curCard) {
      const len = this.infoStore.gameCards.length;
      for (let i = 0; i < len; i++) {
        const card = this.infoStore.gameCards[i];
        if (curCard.cardId === card.cardId) {
          // 选中了自己
          continue;
        }
        // 是否不能点击
        const isUnClick =
          Math.abs(curCard.coor.x - card.coor.x) <= 1 &&
          Math.abs(curCard.coor.y - card.coor.y) <= 1 &&
          curCard.cardId < card.cardId;
        if (isUnClick) {
          console.log("当前卡片无法点击");
          // 如果其他卡片就在'我'附近且cardId大于'我' [位置更高], 则不可点击
          return false;
        }
      }
      return true;
    },
    // 处理抛回的游戏区卡片点击事件 [cardData中包含属性:cardId,iconId,coor]
    handleGameCardClick(cardData) {
      if (!this.infoStore.isStarted) {
        return;
      }
      for (let i = 0; i < this.curNum; i++) {
        const card = this.infoStore.gameCards[i];
        if (card.cardId === cardData.cardId) {
          // 找到了当前点击的卡片 [是否会被遮挡]
          console.log("> 找到了点击的卡片");
          if (!this.isCardClick(card)) {
            // 当前卡片不可点击
            if (this.cardStore.isEdit) {
              this.$message({
                showClose: true,
                message: "当前卡片不可修改, 再重新选择吧",
                type: "warning",
                duration: 3000,
                offset: this.infoStore.popOffset,
              });
            }
            if (this.cardStore.isCover) {
              // 是否考虑遮挡 ['放大镜'效果]
              return;
            }
            this.playVoice(voice1);
            console.log("成功点击一张内部卡片");
          }
          // 卡片是否可修改 ['铅笔'效果]
          if (this.cardStore.isEdit) {
            const editCard = this.cardStore.editCard;
            if (
              editCard !== -1 &&
              !this.infoStore.gameCards.find(
                (item) => item.cardId === editCard.cardId
              )
            ) {
              // 如果已经找不到了 [可能被卡片效果消除了]
              // 弹窗
              this.playVoice(clickVoice);
              this.$message({
                showClose: true,
                message: "要修改的卡片已不在场上, 再重新选择吧",
                type: "warning",
                duration: 3500,
                offset: this.infoStore.popOffset,
              });
              this.$store.commit("cards/setIsEdit", true); // 重置效果
              this.$store.commit("cards/setEditCard", -1);
              return;
            }
            if (editCard === -1) {
              console.log("选中一张卡片");
              this.playVoice(clickVoice, 0.8);
              // 第一次点击
              this.$store.commit("cards/setEditCard", {
                i,
                cardId: card.cardId,
              }); // 记录要修改的卡片 [gameCards中的一项]
            } else {
              console.log("成功编辑卡片");
              this.playVoice(voice1);
              // 第二次点击, 修改第一次点击的卡片
              this.$store.commit("info/setGameCardIcon", {
                i: editCard.i,
                iconId: card.iconId,
              });
              this.$store.commit("cards/setIsEdit", false);
              this.$store.commit("cards/setEditCard", -1);
            }
            return;
          }
          // 是否消除点击的卡片 ['购物袋']
          if (this.cardStore.isDelete) {
            console.log("成功消除一张卡片");
            this.playVoice(voice1);
            this.$store.commit("info/deleteGameCard", i);
            this.$store.commit("cards/setIsDelete", false);
            return;
          }
          // 是否消除点击区域的所有卡片 ['剪刀']
          if (this.cardStore.isDeleteArea) {
            const cards = this.infoStore.gameCards;
            const resultArr = [];
            const len = this.infoStore.gameCards.length;
            for (let j = 0; j < len; j++) {
              const reCard = cards[j];
              // 是否在附近
              if (
                Math.abs(card.coor.x - reCard.coor.x) <= 1 &&
                Math.abs(card.coor.y - reCard.coor.y) <= 1
              ) {
                resultArr.push(j);
              }
            }
            console.log("附近", resultArr);
            // 依次倒删
            for (let j = resultArr.length - 1; j >= 0; j--) {
              this.$store.commit("info/deleteGameCard", resultArr[j]);
            }
            console.log("已删除点击区域的所有卡片");
            this.playVoice(voice1);
            this.$store.commit("cards/setIsDeleteArea", false);
            if (this.curNum === 0) {
              // 全部卡片都已清空
              this.$bus.$emit("gameWin");
            }
            return;
          }
          // 可点击
          // 抛出成功点击事件
          this.$bus.$emit("successClick", {
            cardData: card,
            voice: clickVoice,
            volume: 0.8,
          });
          // 删除第i项 [从卡片数组中移除该卡片]
          this.$store.commit("info/deleteGameCard", i);
          this.$store.commit("cards/setIsCover", true);
          if (this.curNum === 0) {
            // 全部卡片都已清空
            this.$bus.$emit("gameWin");
          }
          break;
        }
      }
    },
    // 游戏开始事件的处理函数 [生成卡片]
    async handleGameStart() {
      if (this.infoStore.isStarted && !this.infoStore.isLevelMode) {
        return;
      }
      // 禁止点击卡片
      this.$store.commit("info/setIsBanCardClick", true);
      const clearCard = this.infoStore.clearCard;
      this.$store.commit("info/setIsStarted", true);
      // 随机生成maxNum个数的卡片
      console.log("生成卡片");
      // 确保卡片数是clearCard的倍数 [让num为clearCard的倍数] [确保有解]
      const num = parseInt(this.cardNum / clearCard) * clearCard;
      if (num !== this.infoStore.cardNum) {
        // 若设置的初始卡片数[cardNum]不能被clearCard整除, 将cardNum设置为clearCard的倍数
        this.$store.commit("info/setCardNum", num);
      }
      if (this.infoStore.isEasy) {
        await this.easyMode(num);
      } else {
        await this.hardMode(num);
      }
      // 允许点击卡片
      this.$store.commit("info/setIsBanCardClick", false);
      // 自动生成卡片 [无尽模式]
      if (this.infoStore.isAutoAddCard && this.infoStore.isStarted) {
      }
    },
    // 增加一张卡片
    async addOneCard(card) {
      // card: { cardId: xxx, iconId: xxx, coor: { x: xxx, y: xxx } }
      console.log("游戏区卡片+1");
      this.$store.commit("info/addGameCard", card); // 加入游戏区的卡片数组中
      this.$store.commit("info/setCardId", card.cardId + 1); // 设置仓库中的卡片id+1
      if (this.infoStore.isAnim) {
        // 生成动画
        await delay(9);
      }
    },
    // 简单模式的卡片生成方式 [也包含最困难模式的生成方式, 但已经弃用[因为容易无解]]
    async easyMode(num) {
      // num: 生成的卡片总数
      const isReduceOverlap = this.infoStore.isReduceOverlap; // 是否降低重叠卡片的概率
      const clearCard = this.infoStore.clearCard;
      // num与3clearCard相除是否有余数
      const isRema = num % (clearCard * 3);
      // 余数与2clearCard相除是否有余数
      const isRemaRema = isRema % (clearCard * 2);
      let iconIdArr = [0, 0, 0];
      let iconIdIndex = 0; // 当前iconId在iconIdArr中的索引
      let iconId = 0; // 每次生成卡片的图标id
      let oldIconId1 = 0; // 记录上一次的iconId1
      let oldCoor = { x: -1, y: -1 }; // 记录当前生成的卡片的前一个卡片的坐标, 用于每次生成不同的坐标
      // console.log(">>>>>2/3:", isRema, isRemaRema);
      for (let i = 0; i < num; i++) {
        if (!this.infoStore.isEasy || i % (clearCard * 3) === 0) {
          // 每(clearCard * 2)次循环变换一次图标 [目的是为了在确保有解的情况下保证一定的难度]
          // 生成不相同的3个随机图标id
          iconIdArr[0] = getRandom(0, this.infoStore.cardTypes.length - 1, [
            oldIconId1,
          ]);
          if (this.infoStore.isEasy) {
            iconIdArr[1] = getRandom(0, this.infoStore.cardTypes.length - 1, [
              iconIdArr[0],
            ]);
            iconIdArr[2] = getRandom(0, this.infoStore.cardTypes.length - 1, [
              iconIdArr[0],
              iconIdArr[1],
            ]);
          }
          oldIconId1 = iconIdArr[1]; // 记录旧iconId
        }
        if (this.infoStore.isEasy) {
          if (i + 1 <= num - isRema) {
            // 让iconId在clearCard个数据中交替变换
            iconIdIndex = (iconIdIndex + 1) % 3;
            iconId = iconIdArr[iconIdIndex];
          } else {
            // 倒数 3clearCard的余数 次的循环
            if (!isRemaRema) {
              // 如果num对3clearCard余数能被2clearCard整除
              // iconId在2个数据中交替变换
              iconId = i % 2 === 0 ? iconIdArr[0] : iconIdArr[1];
            } else {
              // console.log("> iconId不变换");
            }
          }
        } else {
          iconId = iconIdArr[0];
        }
        // console.log(`${i + 1}.iconId:`, iconId);
        const coor = {
          // 生成与前一个卡片不同的坐标
          x: getRandom(
            0,
            this.infoStore.size.w - 1,
            isReduceOverlap ? [oldCoor.x] : []
          ),
          y: getRandom(
            0,
            this.infoStore.size.h - 1,
            isReduceOverlap ? [oldCoor.y] : []
          ),
        };
        const card = {
          cardId: this.infoStore.cardId,
          iconId: this.infoStore.cardTypes[iconId],
          coor,
        };
        oldCoor = coor; // 记录当前卡片的坐标
        await this.addOneCard(card);
      }
    },
    // 困难模式
    async hardMode(num) {
      // num: 生成的卡片总数
      const clearCard = this.infoStore.clearCard;
      let iconId = 0; // 每次生成卡片的图标id
      let oldIconId = -1; // 记录上一次的iconId1
      let oldCoor = { x: -1, y: -1 }; // 记录当前生成的卡片的前一个卡片的坐标, 用于每次生成不同的坐标
      const cardArr = []; // 创建的卡片的数组
      // 创建卡片
      for (let i = 0; i < num; i++) {
        if (i % clearCard === 0) {
          // 每clearCard次变换一次图标
          // 生成随机图标id
          iconId = getRandom(0, this.infoStore.cardTypes.length - 1, [
            oldIconId,
          ]);
          oldIconId = iconId; // 记录旧iconId
        }
        const coor = {
          // 生成与前一个卡片不同的坐标
          x: getRandom(0, this.infoStore.size.w - 1, [oldCoor.x]),
          y: getRandom(0, this.infoStore.size.h - 1, [oldCoor.y]),
        };
        cardArr.push({
          cardId: -1,
          iconId: this.infoStore.cardTypes[iconId],
          coor,
        });
        oldCoor = coor; // 记录当前卡片的坐标
      }
      const len = cardArr.length;
      // 生成卡片
      for (let i = 0; i < num; i++) {
        const index = getRandom(0, len - i - 1); // 随机的卡片索引
        cardArr[index].cardId = this.infoStore.cardId;
        await this.addOneCard(cardArr[index]);
        cardArr.splice(index, 1); // 删除
      }
    },
  },
};
</script>

<style lang="less" scoped>
@import "~@/styles/var.less";

.game-area-container {
  .area-container {
    position: relative;
  }
  margin: 0 auto;
  margin-top: 20px;
  margin-bottom: 50px;
  padding: 12px;
  border: 3px solid @gameBor;
  border-radius: 10px;
  .versions {
    position: absolute;
    font-size: 13px;
    bottom: -50px;
    right: -15px;
    color: #c6c6c6;
  }
  .msg {
    position: absolute;
    font-size: 13px;
    bottom: -50px;
    left: -15px;
    color: #c6c6c6;
  }
  .curCardNum {
    position: absolute;
    font-size: 13px;
    top: -35px;
    right: -15px;
    color: #c6c6c6;
  }
}
</style>
